import { observable, autorun, configure, action, runInAction } from "mobx";
// observable 定义一个存储 state 的可追踪（可观察）字段。
// 由 observable 返回的对象将会使用 Proxy 包装，
// 这意味着之后被添加到这个对象中的属性也将被侦测并使其转化为可观察对象（除非禁用 proxy）。

// .box()对普通类型数据监听
// const value = observable.box(0);
// const number = observable.box(100);

// autorun 函数（监听函数）接受一个函数作为参数，每当该函数所观察的值发生变化时，它都应该运行。
// 当创建 autorun 时，它也会运行一次。它仅仅对可观察状态的变化做出响应，
// 比如那些用 observable 或者 computed 注释的。
// autorun(() => {
//     // get获取监听的值
//     console.log("value-->", value.get()); //0,1,2。 // autorun 使用到才能被执行 只能是同步，异步需要处理
// });
// // set修改被监听的值
// value.set(1);
// value.set(2);
// number.set(101);

//观察对象，通过map
// const map = observable.map({ key: "value" });
// autorun(() => {
//     console.log("map-->", map.get("key")); // value,new value,new new value
// });
// map.set("key", "new value");
// map.set("key", "new new value");

// 观察对象，不通过map
// const map = observable({ key: "value", name: "小白" });
// autorun(() => {
//     // autorun精确追踪
//     console.log("map-->", map.key); // value,xiaoming,xiaohong
// });
// map.key = "xiaoming";
// map.name = "大白"; // name改变不会触发上述仅含有key的autorun执行
// map.key = "xiaohong";

//观察数组
// let list = observable([1, 2, 4]);
// autorun(() => {
//     console.log("list-->", list[0]); // 1,3,2
// });
// list[0] = 3;
// list.shift();
// list = [9];

// 严格模式
configure({
    enforceActions: "always", // 总是强制只能在store内部修改状态
});

// 定义全局状态store并导出
// const store = observable(
//     {
//         // 定义状态：state
//         isShow: true,
//         list: [],
//         home: true,
//         // 定义修改状态的方法：action
//         changeShow() {
//             this.isShow = true;
//         },
//         changeHide() {
//             this.isShow = false;
//         },
//         changeHome() {
//             this.home = !this.home;
//         },
//         // 异步修改状态
//         getList() {
//             setTimeout(() => {
//                 const res = [1, 2, 3];
//                 // 在启用严格模式时不能在异步中修改状态
//                 // 会报：不允许在操作之外更改观察到的可观察值的错误
//                 // this.list = res;

//                 // 严格模式下，异步中调用runInAction修改状态
//                 runInAction(() => {
//                     this.list = res;
//                 });
//             }, 1000);
//         },
//     },
//     // 标记哪些是action，专门修改可观察的状态
//     {
//         changeHide: action,
//         changeShow: action,
//         changeHome: action,
//         getList: action,
//     }
// );

// 装饰器写法(Mobx6之前提倡的写法)：
// 配置支持装饰器：
// 1.安装npm i @babel/core @babel/plugin-proposal-decorators @babel/preset-env
// 2.根目录下创建.babelrc，写入：
// {
//     "presets": [
//         "@babel/preset-env"
//     ],
//     "plugins": [
//         [
//             "@babel/plugin-proposal-decorators",
//             {
//                 "legacy": true
//             }
//         ]
//     ]
// }
// 3.根目录下创建config-overrides.js（作用是重写部分react配置文件，使其支持装饰器），写入：
// const path = require("path");
// const { override, addDecoratorsLegacy } = require("customize-cra");
// function resolve(dir) {
//     return path.join(__dirname, dir);
// }
// const customize = () => (config, env) => {
//     config.resolve.alias["@"] = resolve("src");
//     if (env === "production") {
//         config.externals = {
//             react: "React",
//             "react-dom": "ReactDOM",
//         };
//     }
//     return config;
// };
// module.exports = override(addDecoratorsLegacy(), customize());
// 4.安装npm i customize-cra react-app-rewired，作用是使config-overrides.js生效
// 5.修改package.json：（作用是使react npm脚本按照react-app-rewired走，可使config-overrides.js生效）
// ...
//     "scripts": {
//     "start": "react-app-rewired start",
//     "build": "react-app-rewired build",
//     "test": "react-app-rewired test",
//     "eject": "react-app-rewired eject"
//     },
// ...
// 6.解决VScode报错问题：打开设置搜索experimentalDecorators，勾选即可
class Store {
    // @observable装饰一个数据为可观测数据
    @observable isShow = true;
    @observable list = [];
    @observable home = true;
    // @action 装饰一个函数为修改状态的action函数
    @action changeShow() {
        this.isShow = true;
    }
    @action changeHide() {
        this.isShow = false;
    }
    @action changeHome() {
        this.home = !this.home;
    }
    // 异步修改状态
    @action getList() {
        setTimeout(() => {
            const res = [1, 2, 3];
            // 在启用严格模式时不能在异步中修改状态
            // 会报：不允许在操作之外更改观察到的可观察值的错误
            // this.list = res;

            // 严格模式下，异步中调用runInAction修改状态
            runInAction(() => {
                this.list = res;
            });
        }, 1000);
    }
}
// 装饰器的作用类似于高阶组件，接收一个低级东西，吐出一个高级东西
const store = new Store();
// 在Mobx6中已经弃用装饰器写法！！！

export default store;
